﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using General.Entities.Dapper;
using General.Entities.Models;
using General.Framework;
using General.Mvc.Filters;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace General.Mvc.Controllers.Admin
{
    [Route("api/admin/[controller]/[action]")]
    [ApiController]
    [ServiceFilter(typeof(ResponseLogTimeFilter))]
    public class CodeController : Controller
    {
        private readonly ILogger<CodeController> logger;

        private DbRepository dbRepository { get; set; }
        public CodeController(ILogger<CodeController> logger)
        {
            this.logger = logger;
        }

        //1:MySQL 2:SQLServer

        /// <summary>
        /// 获取默认链接字符串
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [ServiceFilter(typeof(AdminCheckFilter))]
        public IActionResult GetDBType(int id)
        {
            AjaxResult result = new AjaxResult();
            var connStr = "";
            switch (id)
            {
                case 1:
                    connStr = "Data Source=127.0.0.1;Database=test;User ID=root;Password=123456;pooling=true;CharSet=utf8;port=3306;sslmode=none";
                    break;
                case 2:
                    connStr = "Data Source=.;Initial Catalog=test;Persist Security Info=True;User ID=sa;Password=123456";
                    break;
                default:
                    connStr = "获取失败";
                    break;
            }
            result.code = AjaxResultStateEnum.Ok;
            result.message = "获取成功!";
            result.data = connStr;
            return Content(JsonHelper.Serialize(result));
        }


        /// <summary>
        /// 初始化数据库链接
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ServiceFilter(typeof(AdminCheckFilter))]
        public async Task<IActionResult> InitDBConnection([FromForm] int id, [FromForm] string connStr)
        {
            AjaxResult result = new AjaxResult();
            var ConnStrDict = new ConcurrentDictionary<string, string>();
            ConnStrDict.TryAdd("connStr", connStr);
            DbConnectionFactory.connStrDict = ConnStrDict;
            var sqlStr = string.Empty;
            var dbName = string.Empty;
            var tableList = new List<DBTable>();
            try
            {
                //初始化dapper
                switch (id)
                {
                    case 1:
                        dbRepository = new DbRepository("connStr", DbType.MySql);
                        sqlStr = "show tables;";
                        Regex reg = new Regex("Database=(.+);");
                        Match match = reg.Match(connStr);
                        dbName = match.Groups[1].Value;
                        var dataReader = await dbRepository.QueryAsync<object>("show tables;");
                        foreach (var item in dataReader)
                        {
                            var temp = item.ToString();
                            Regex reg2 = new Regex("'(.+)'");
                            Match match2 = reg2.Match(temp);
                            DBTable bTable = new DBTable();
                            bTable.name = match2.Groups[1].Value;
                            tableList.Add(bTable);
                        }
                        break;
                    case 2:
                        dbRepository = new DbRepository("connStr", DbType.SqlServer);
                        sqlStr = "SELECT name FROM SYSOBJECTS WHERE XTYPE='U' ORDER BY NAME";
                        var list = await dbRepository.QueryAsync<DBTable>(sqlStr);
                        tableList = list.ToList();
                        break;
                    default:
                        result.code = AjaxResultStateEnum.Fail; result.message = "数据库选择错误";
                        return Content(JsonHelper.Serialize(result));
                }

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "生成代码字符串链接失败！");
                result.code = AjaxResultStateEnum.Fail;
                result.message = "链接失败";
                return Content(JsonHelper.Serialize(result));
            }

            result.code = AjaxResultStateEnum.Ok;
            result.data = tableList;
            result.message = "获取成功";
            return Content(JsonHelper.Serialize(result));
        }


        /// <summary>
        /// 生成模型代码
        /// </summary>
        /// <param name="id">数据库类型</param>
        /// <param name="tablename">表名称</param>
        /// <param name="type">1.预展代码 2.生成文件</param>
        /// <returns></returns>
        [HttpPost]
        [ServiceFilter(typeof(AdminCheckFilter))]
        public async Task<IActionResult> OutPutModel([FromServices] IWebHostEnvironment environment, [FromForm] int id, [FromForm] string tablename, [FromForm] int type)
        {
            AjaxResult result = new AjaxResult();
            var columnList = new List<DBColumn>();
            try
            {
                switch (id)
                {
                    case 1:
                        dbRepository = new DbRepository("connStr", DbType.MySql);
                        var mysqlList = await dbRepository.QueryAsync<MySQLColumn>($"select column_name,data_type from information_schema.columns where table_name = '{tablename}';");
                        foreach (var item in mysqlList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.column_name,
                                isKey = false,
                                type_name = item.data_type
                            };
                            columnList.Add(temp);
                        }
                        break;
                    case 2:
                        dbRepository = new DbRepository("connStr", DbType.SqlServer);
                        var sqlserverList = await dbRepository.QueryAsync<SQLServerColumn>($"sp_columns {tablename};");
                        foreach (var item in sqlserverList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.COLUMN_NAME,
                                isKey = false,
                                type_name = item.TYPE_NAME
                            };
                            columnList.Add(temp);
                        }
                        break;
                    default:
                        result.code = AjaxResultStateEnum.Fail; result.message = "数据库选择错误";
                        return Content(JsonHelper.Serialize(result));
                }

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "生成代码模型失败！");
                result.code = AjaxResultStateEnum.Fail;
                result.message = "生成代码模型失败";
                return Content(JsonHelper.Serialize(result));
            }
            columnList = DBColumnsTypeProcess(columnList);


            var GetPath = environment.WebRootPath + "/templete/DBTableModel.html";
            var DBTableModelTemp = await System.IO.File.ReadAllTextAsync(GetPath);
            DBTableModelTemp = DBTableModelTemp.Replace("{TableName}", tablename);
            var Parms = string.Empty;
            foreach (var item in columnList)
            {
                if (item.isKey)
                {
                    Parms += "        [Key]\r\n";
                }
                Parms += "        public " + item.type_name+" "+item.column_name+ " { get; set; }\r\n";
            }
            DBTableModelTemp = DBTableModelTemp.Replace("{Parms}", Parms);

            if (type == 1)
            {
                DBTableModelTemp = DBTableModelTemp.Replace("\n", "<br />");
                result.data = DBTableModelTemp;
                result.code = AjaxResultStateEnum.Ok;
                result.message = "生成成功!";
                return Content(JsonHelper.Serialize(result));
            }
            else if (type == 2)
            {
                //var WritePath = environment.ContentRootPath.Replace(environment.ApplicationName, "") + "/General.Entities/Models/" + tablename + ".cs";
                var WritePath = environment.ContentRootPath.Replace("General.Mvc", "") + "General.Entities/Models/" + tablename + ".cs";
                await System.IO.File.WriteAllTextAsync(WritePath, DBTableModelTemp);
                var DBContextPath = environment.ContentRootPath.Replace("General.Mvc", "") + "General.Entities/GeneralDbContext.cs";
                var DBContextContent = await System.IO.File.ReadAllTextAsync(DBContextPath);
                DBContextContent = DBContextContent.Replace("{CodeGeneration}", "{CodeGeneration}\n        public DbSet<Models." + tablename + "> "+ tablename + " { get; set; }");
                await System.IO.File.WriteAllTextAsync(DBContextPath, DBContextContent);
                result.code = AjaxResultStateEnum.Ok;
                result.message = "生成成功!";
                return Content(JsonHelper.Serialize(result));
            }
            else
            {
                result.code = AjaxResultStateEnum.Fail;
                result.message = "参数错误!";
                return Content(JsonHelper.Serialize(result));
            }
        }



        /// <summary>
        /// 生成Service代码
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ServiceFilter(typeof(AdminCheckFilter))]
        public async Task<IActionResult> OutPutService([FromServices] IWebHostEnvironment environment, [FromForm] int id, [FromForm] string tablename, [FromForm] string servicename, [FromForm] int type)
        {
            AjaxResult result = new AjaxResult();
            var columnList = new List<DBColumn>();
            try
            {
                switch (id)
                {
                    case 1:
                        dbRepository = new DbRepository("connStr", DbType.MySql);
                        var mysqlList = await dbRepository.QueryAsync<MySQLColumn>($"select column_name,data_type from information_schema.columns where table_name = '{tablename}';");
                        foreach (var item in mysqlList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.column_name,
                                isKey = false,
                                type_name = item.data_type
                            };
                            columnList.Add(temp);
                        }
                        break;
                    case 2:
                        dbRepository = new DbRepository("connStr", DbType.SqlServer);
                        var sqlserverList = await dbRepository.QueryAsync<SQLServerColumn>($"sp_columns {tablename};");
                        foreach (var item in sqlserverList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.COLUMN_NAME,
                                isKey = false,
                                type_name = item.TYPE_NAME
                            };
                            columnList.Add(temp);
                        }
                        break;
                    default:
                        result.code = AjaxResultStateEnum.Fail; result.message = "数据库选择错误";
                        return Content(JsonHelper.Serialize(result));
                }

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "生成代码失败！");
                result.code = AjaxResultStateEnum.Fail;
                result.message = "生成代码失败";
                return Content(JsonHelper.Serialize(result));
            }
            columnList = DBColumnsTypeProcess(columnList);
            var IServicePath = environment.WebRootPath + "/templete/IServiceTemplete.html";
            var IServicePathTemp = await System.IO.File.ReadAllTextAsync(IServicePath);
            IServicePathTemp = IServicePathTemp.Replace("{TableName}", tablename);
            IServicePathTemp = IServicePathTemp.Replace("{ServiceName}", servicename);

            var ServicePath = environment.WebRootPath + "/templete/ServiceTemplete.html";
            var ServicePathTemp = await System.IO.File.ReadAllTextAsync(ServicePath);
            ServicePathTemp = ServicePathTemp.Replace("{TableName}", tablename);
            ServicePathTemp = ServicePathTemp.Replace("{ServiceName}", servicename);
            var parms = string.Empty;
            var parms2 = string.Empty;
            foreach (var item in columnList)
            {
                parms += item.column_name+"=d."+ item.column_name+",";
                if (item.column_name != "id")
                {
                    parms2 += "            model." + item.column_name + " = data." + item.column_name + ";\n";
                }
            }
            ServicePathTemp = ServicePathTemp.Replace("{Parms}", parms);
            ServicePathTemp = ServicePathTemp.Replace("{Parms2}", parms2);
            if (type == 1)
            {
                IServicePathTemp = IServicePathTemp.Replace("\n", "<br />");
                ServicePathTemp = ServicePathTemp.Replace("\n", "<br />");
                result.data = IServicePathTemp+"\n\n\n"+ ServicePathTemp;
                result.code = AjaxResultStateEnum.Ok;
                result.message = "生成成功!";
                return Content(JsonHelper.Serialize(result));
            }
            else if (type == 2)
            {
                var WriteServicePath = environment.ContentRootPath.Replace("General.Mvc", "") + "General.Services/" + tablename;
                if (!Directory.Exists(WriteServicePath))
                {
                    Directory.CreateDirectory(WriteServicePath);
                }
                await System.IO.File.WriteAllTextAsync(WriteServicePath+ "/I"+servicename+".cs", IServicePathTemp);
                await System.IO.File.WriteAllTextAsync(WriteServicePath + "/" + servicename + ".cs", ServicePathTemp);
               
                result.code = AjaxResultStateEnum.Ok;
                result.message = "生成成功!";
                return Content(JsonHelper.Serialize(result));
            }
            else
            {
                result.code = AjaxResultStateEnum.Fail;
                result.message = "参数错误!";
                return Content(JsonHelper.Serialize(result));
            }
        }

        /// <summary>
        /// 生成前端代码
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ServiceFilter(typeof(AdminCheckFilter))]
        public async Task<IActionResult> OutPutHtml([FromServices] IWebHostEnvironment environment, [FromForm] int id, [FromForm] string tablename)
        {
            AjaxResult result = new AjaxResult();
            var columnList = new List<DBColumn>();
            try
            {
                switch (id)
                {
                    case 1:
                        dbRepository = new DbRepository("connStr", DbType.MySql);
                        var mysqlList = await dbRepository.QueryAsync<MySQLColumn>($"select column_name,data_type from information_schema.columns where table_name = '{tablename}';");
                        foreach (var item in mysqlList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.column_name,
                                isKey = false,
                                type_name = item.data_type
                            };
                            columnList.Add(temp);
                        }
                        break;
                    case 2:
                        dbRepository = new DbRepository("connStr", DbType.SqlServer);
                        var sqlserverList = await dbRepository.QueryAsync<SQLServerColumn>($"sp_columns {tablename};");
                        foreach (var item in sqlserverList)
                        {
                            DBColumn temp = new DBColumn()
                            {
                                column_name = item.COLUMN_NAME,
                                isKey = false,
                                type_name = item.TYPE_NAME
                            };
                            columnList.Add(temp);
                        }
                        break;
                    default:
                        result.code = AjaxResultStateEnum.Fail; result.message = "数据库选择错误";
                        return Content(JsonHelper.Serialize(result));
                }

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "生成代码失败！");
                result.code = AjaxResultStateEnum.Fail;
                result.message = "生成代码失败";
                return Content(JsonHelper.Serialize(result));
            }
            columnList = DBColumnsTypeProcess(columnList);
            var HtmlPath = environment.WebRootPath + "/templete/AdminCsHtmlTemplete.html";
            var HtmlPathTemp = await System.IO.File.ReadAllTextAsync(HtmlPath);
            HtmlPathTemp = HtmlPathTemp.Replace("{TableName}", tablename);
            var Parms1 = string.Empty;
            var Parms2 = string.Empty;
            foreach (var item in columnList)
            {
                if (item.column_name == "id")
                {
                    continue;
                }
                Parms1 += @"
        <div class='layui-form-item'>
            <label class='layui-form-label layui-form-required'>"+item.column_name+ @":</label>
            <div class='layui-input-block'>
                <input name='" + item.column_name + @"' placeholder='请输入" + item.column_name + @"' class='layui-input'
                       lay-verType='tips' lay-verify='required' required />
            </div>
        </div>";
                Parms2 += "                {field: '" + item.column_name + "', title: '" + item.column_name + "', sort: true},\n";
            }
            HtmlPathTemp = HtmlPathTemp.Replace("{Parms1}", Parms1);
            HtmlPathTemp = HtmlPathTemp.Replace("{Parms2}", Parms2);


            result.code = AjaxResultStateEnum.Ok;
            result.message = "生成成功!";
            result.data = HtmlPathTemp;
            return Content(JsonHelper.Serialize(result));
        }


        /// <summary>
        /// test
        /// </summary>
        /// <param name="environment"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> Test([FromServices] IWebHostEnvironment environment)
        {
            var DBContextPath = environment.ContentRootPath.Replace(environment.ApplicationName, "") + "General.Entities/GeneralDbContext.cs";
            var DBContextContent = await System.IO.File.ReadAllTextAsync(DBContextPath);

            return Content("");
        }
      

        /// <summary>
        /// 数据表
        /// </summary>
        public class DBTable
        {
            public string name { get; set; }
        }

        /// <summary>
        /// MySQL表字段
        /// </summary>
        public class MySQLColumn
        {
            public string column_name { get; set; }
            public string data_type { get; set; }
        }

        /// <summary>
        /// SQLServer表字段
        /// </summary>
        public class SQLServerColumn
        {
            public string COLUMN_NAME { get; set; }
            public string TYPE_NAME { get; set; }
        }

        /// <summary>
        /// 公用表字段
        /// </summary>
        public class DBColumn
        {
            public string column_name { get; set; }
            public string type_name { get; set; }
            public bool isKey { get; set; }
        }

        /// <summary>
        /// 数据类型转化方法
        /// </summary>
        /// <returns></returns>
        private List<DBColumn> DBColumnsTypeProcess(List<DBColumn> columnList)
        {
            foreach (var item in columnList)
            {
                if (item.column_name == "id")
                {
                    item.isKey = true;
                }
                switch (item.type_name)
                {
                    case "int identity":
                        item.type_name = "int";
                        break;
                    case "int":
                        item.type_name = "int";
                        break;
                    case "tinyint":
                        item.type_name = "int";
                        break;
                    case "nvarchar":
                        item.type_name = "string";
                        break;
                    case "varchar":
                        item.type_name = "string";
                        break;
                    case "char":
                        item.type_name = "string";
                        break;
                    case "datetime":
                        item.type_name = "DateTime";
                        break;
                    case "date":
                        item.type_name = "DateTime";
                        break;
                    case "bigint":
                        item.type_name = "long";
                        break;
                    case "bit":
                        item.type_name = "int";
                        break;
                    case "decimal":
                        item.type_name = "decimal";
                        break;
                    case "float":
                        item.type_name = "float";
                        break;
                    case "money":
                        item.type_name = "decimal";
                        break;
                    case "nchar":
                        item.type_name = "string";
                        break;
                    case "ntext":
                        item.type_name = "string";
                        break;
                    case "text":
                        item.type_name = "string";
                        break;
                    case "smallint":
                        item.type_name = "int";
                        break;
                    case "time":
                        item.type_name = "DateTime";
                        break;
                    default:
                        item.type_name = "string";
                        break;
                }
                
            }
            return columnList;
        }
    }
}
